package com.uinnova.product.eam.web.config.mvc;

import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.lang.StringUtils;
import com.uinnova.project.base.diagram.util.RedisUtil;
import com.uino.api.client.permission.IOauthApiSvc;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.permission.base.OauthResourceDetail;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.business.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.HttpCookie;
import java.util.List;

/**
 * 对接太保免费登录
 *
 * @author lichong
 * @since 2022/6/6 13:43
 */
@WebFilter(urlPatterns = "/*")
@Component
@Order(1)
@Slf4j
@ConditionalOnProperty(name = "monet.login.loginMethod", havingValue = "taibao")
public class TAIBAOSSOLoginFilter implements Filter {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private IUserApiSvc userSvc;

    @Autowired
    IOauthApiSvc oauthApiSvc;

    @Value("${taibao.test.ticket:false}")
    private Boolean enableTaibaoAdmin;

    @Value("${server.servlet.context-path:/}")
    private String contextPath;

    @Value("${taibao.login.url:http://29.4.0.155/pages/workbench.html}")
    private String oauthServerUrl;

    @Value("${taibao.userdata.url:http://29.23.13.23:31001/portal2/api/user/getUserForEa}")
    private String userDataUrl;

    public static final String taibaiUserProfile = "EA:TAIBAI:USER:";

    /**
     * 用户在redis存储时间1800秒（30分钟）
     */
    public static final long userTicketOutTime =1800L;

    {
        log.info("太保登录拦截器注册成功");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse rep, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) rep;
        //接口过滤
        String requestUri = request.getRequestURI();
        requestUri = StrUtil.sub(requestUri, requestUri.indexOf(contextPath) + contextPath.length(), requestUri.length());
        OauthResourceDetail resourceDetail = oauthApiSvc.getResourceDetail(contextPath.replace("/", ""));
        List<String> permitAllUrls = resourceDetail.getPermitAllUrls();
        String finalRequestUri = requestUri;
        boolean isPermitFlag = permitAllUrls
                .stream()
                .anyMatch(permitUrl -> ReUtil.isMatch(permitUrl.trim(), finalRequestUri));
        if (isPermitFlag) {
            chain.doFilter(req, rep);
        } else {
            String ticket = request.getParameter("ticket");
            // 若url中没有ticket则从cookie中获取
            if (StringUtils.isEmpty(ticket)) {
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        if ("ticket".equals(cookie.getName())) {
                            ticket = cookie.getValue();
                        }
                    }
                }
            }
            //没有携带token则直接跳转it云平台登录
            if (StringUtils.isEmpty(ticket)) {
                response.sendRedirect(oauthServerUrl);
            } else {
                String redisTicket = taibaiUserProfile + ticket;
                //若redis不存在或者token已过期则重新从太保用户系统获取数据
                if (redisUtil.get(redisTicket) == null) {
                    if (enableTaibaoAdmin && ticket.equals("123456")) {
                        String taibaoUser = "{\n" +
                                "    \"userCode\": \"admin\",\n" +
                                "    \"success\":200\n" +
                                "}";
                        SysUser sysUser = converUserToEa(taibaoUser);
                        redisUtil.set(redisTicket, sysUser, userTicketOutTime);
                    } else {
                        HttpCookie httpCookie = new HttpCookie("ticket", ticket);
                        HttpRequest ticketRequest = HttpRequest.get(userDataUrl).cookie(httpCookie).timeout(20000);
                        HttpResponse execute = ticketRequest.execute();
                        int status = execute.getStatus();
                        if (HttpStatus.HTTP_OK == status) {
                            String taibaoUser = execute.body();
                            log.debug("太保用户接口返回数据:{}", taibaoUser);
                            SysUser sysUser = converUserToEa(taibaoUser);
                            redisUtil.set(redisTicket, sysUser, userTicketOutTime);
                        } else {
                            log.info("获取太保用户失败:{}", execute);
                            throw new RuntimeException("请求认证服务器获取用户失败");
                        }
                    }
                }
                request.setAttribute("taibaoTicket", ticket);
                chain.doFilter(req, rep);
            }
        }
    }

    private SysUser converUserToEa(String taibaoUser) {
        log.debug("太保用户数据：{}", taibaoUser);
        // 校验用户并转换用户
        JSONObject jsonObject = JSON.parseObject(taibaoUser);
        Integer success = jsonObject.getInteger("success");
        if (HttpStatus.HTTP_OK != success) {
            throw new RuntimeException("获取认证失败:" + taibaoUser);
        }
        String loginCode = jsonObject.getString("userCode");
        //从ea库查询用户信息
        UserInfo userInfo = userSvc.getUserInfoByLoginCode(loginCode);
        if (userInfo == null) {
            throw new RuntimeException("用户不存在，请联系管理员");
        }
        log.debug("获取ea用户：{}", userInfo);
        return userInfo;
    }

}
